package controllers

import (
	"time"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/gorilla/websocket"
	."LiquidMeasurement/forms"
	m"LiquidMeasurement/models"
)

type DevicePoolController struct {
	beego.Controller
}
type  DeviceInfo struct{
	LastCollection  int64
	LastHeartCount	uint64
	HeartCount 		uint64

	*DeviceConnForm

}
//创建变量
var (
// 加入连接池的数据信道
	subscribe = make(chan DeviceScript, 1000)
	//加入连接池的网关设备信道
	subscribe_gateway = make(chan DeviceScript, 1000)

//发送信息给指定设备
	msgscribe = make(chan MsgScrpt, 1000)
//	更新温度及湿度的信道
	//update_temperature = make(chan DeviceScript, 1000)
//	更新开关的信道
//	update_switch = make(chan DeviceScript, 1000)
//设备掉线的信道
	unsubscribe = make(chan DeviceConnForm, 1000)
	unsubscribe_gateway = make(chan string, 1000)

//	改变设备状态的信道
	//Change_device_status = make(chan REQ_RESP_Type, 1000)
//用于存储连接数据的连接池
	devices = make(map[string] DevicePoll)
	err_devices = make(map[string] DevicePoll)
//用于要发送信息的连接池
	//send_channel = make(chan MsgScript, 1000)
	//心跳包附带的消息
	heart_msg = make(chan DeviceConnForm,1000)

)

type Callback func (msg string) int
//用于描述连接池中设备的数据结构，连接描述符
type DeviceScript struct {
	GateMac 				string				//设备的macf地址
	IsBusy				int					//设备是否处于忙的状态
	Conn 				*websocket.Conn // websocket连接的句柄
	UnixTime			int64
	Device_Info        DeviceInfo
}


type DevicePoll struct {
	GateMac 				string				//设备的macf地址
	IsBusy				int					//设备是否处于忙的状态
	Conn 				*websocket.Conn // websocket连接的句柄
	UnixTime			int64
	DeviceInfoMap       map[string]  DeviceInfo
}

type MsgScrpt struct  {
	Mac 				string				//设备的macf地址
	Msg                 []byte
}

//设备加入websocket连接池
func JoinDevice(ws *websocket.Conn,mac string,info DeviceConnForm) {
	fmt.Println("info:",info)
	conn := DeviceConnForm{Mac:info.Mac,DeviceID:info.DeviceID,ShortAddr:info.ShortAddr,DeviceType:info.DeviceType,BindID:info.BindID,Optype:info.Optype,DataList:info.DataList,PowerEnenge:info.PowerEnenge,Msg:info.Msg,ResponeCode:info.ResponeCode}
    _info  := DeviceInfo{-1,0,0,&conn}//info.(DeviceInfo)
//	fmt.Println(_info)
//	map_info := make(map[string] DeviceInfo)
//	map_info[_info.DeviceID] = _info
//	fmt.Println(map_info)
	subscribe <- DeviceScript{GateMac: mac, Conn: ws,IsBusy:0,UnixTime:time.Now().Unix(),Device_Info:_info}//加入信道
}

//设备加入websocket连接池
func JoinGateWay(ws *websocket.Conn,mac string) {
	//fmt.Println("info:",info)

	_info  := DeviceInfo{}//info.(DeviceInfo)
	//	fmt.Println(_info)
	//	map_info := make(map[string] DeviceInfo)
	//	map_info[_info.DeviceID] = _info
	//	fmt.Println(map_info)
	subscribe_gateway <- DeviceScript{GateMac: mac, Conn: ws,IsBusy:0,UnixTime:time.Now().Unix(),Device_Info:_info}//加入信道
}

//网关设备离开websocket连接池
func LeaveGateway(mac string) {
	unsubscribe_gateway <- mac				//加入信道
}


//液位设备离开websocket连接池
func LeaveDevice(device DeviceConnForm) {
	unsubscribe <- device				//加入信道
}

//液位设备心跳包
func DeviceHeart(device DeviceConnForm) {
	heart_msg <- device				//加入信道
}



//将设备加入到连接池
func addDevice(device DeviceScript){
	//devices[device.GateMac].DeviceInfoMap[device.Device_Info.DeviceID]
		_,gate_exit := devices[device.GateMac]
		if gate_exit == false{
			map_info := make(map[string] DeviceInfo)
			map_info[device.Device_Info.DeviceID] = device.Device_Info
			devices[device.GateMac] = DevicePoll{GateMac:device.GateMac,IsBusy:device.IsBusy,Conn:device.Conn,UnixTime:device.UnixTime,DeviceInfoMap:map_info}
		}else{
			devices[device.GateMac].DeviceInfoMap[device.Device_Info.DeviceID] = device.Device_Info
		}
	    fmt.Println(devices[device.GateMac].DeviceInfoMap)
//		_, ok := devices[device.GateMac].DeviceInfoMap[device.Device_Info.DeviceID]
//	    if ok == false{
//
//		}else{
//			devices[device.GateMac].DeviceInfoMap[device.Device_Info.DeviceID] = device.Device_Info
//		}
// = DevicePoll{GateMac:device.GateMac,IsBusy:device.IsBusy,Conn:device.Conn,UnixTime:device.UnixTime,DeviceInfoMap:map_info};
}


//将网关加入到连接池
func addGateway(device DeviceScript){
	map_info := make(map[string] DeviceInfo)
	//map_info[device.Device_Info.DeviceID] = device.Device_Info
	devices[device.GateMac] = DevicePoll{GateMac:device.GateMac,IsBusy:device.IsBusy,Conn:device.Conn,UnixTime:device.UnixTime,DeviceInfoMap:map_info};
}
//通过mac地址获取设备的地址
func getDeviceInfo(mac string)(DevicePoll)  {
	return devices[mac]
}


type BedDeviceInfo struct {
	Device  DeviceInfo
	Bed		m.BedResponeModel
}
//通过mac地址获取所有设备的地址
func GetAllDevicesInfo()([]BedDeviceInfo)  {
	fmt.Println("devices",devices)
	mySlice := make([]BedDeviceInfo, 0, 10000)
    for _,v :=  range(devices){
		//fmt.Println("k:%s",k)
		for _,device := range(v.DeviceInfoMap){
			if device.BindID != 0{
				bed,_ := m.GetBedByBedID(device.BindID)
				mySlice = append(mySlice , BedDeviceInfo{device,bed})
			}
		}
	}
	return mySlice
}

//将连接从连接池中移除
//@param mac  string   网关的mac地址
//@param DeviceID  string   设备的DeviceID地址
func removeDevice(mac string ,DeviceID string){
	delete(devices[mac].DeviceInfoMap, DeviceID)
}

//将网关连接从连接池中移除
//@param mac  string   网关的mac地址
//@param DeviceID  string   设备的DeviceID地址
func removeGateway(mac string){
	//delete(devices[mac].DeviceInfoMap,mac)
}

//替换连接池中的连接
func replaceGateway(device DeviceScript){

	old_device := devices[device.GateMac]
	old_device.Conn = device.Conn
	devices[device.GateMac] = old_device
	fmt.Println("replace gateway ok  mac:",device.GateMac)
	//	if err := old_device.Conn.Close(); err != nil {
	//		//return err
	//		fmt.Println("close conn srror")
	//	}
	//devices[device.Mac] = device;

}

//向设备发送json数据
//@param data  []byte   要发送的json数据序列化后的字节流
//@param ws  websocket.Conn   websocket句柄
func sendJson(data []byte,device DevicePoll)(bool){
	defer func() {
		if r := recover(); r != nil {
			beego.Debug("Runtime error caught: %v", r)
		}
	}()
	if device.Conn == nil{
		fmt.Println("device.Conn is nil")
		return false
	}
	fmt.Println("send json data",string(data))
	if err := device.Conn.WriteMessage(websocket.TextMessage, data); err != nil {
		fmt.Println("herat err",err)
		return false
	}
	return true
}

//给链接池中的设备发送心跳包同时附上相应的数据
//@param null  null  无
func HeartBeat(info DeviceConnForm) (uint8){
	_device ,ok:= devices[info.Mac].DeviceInfoMap[info.DeviceID]
	if(ok){
		_device.DataList[0]  =info.DataList[0]
		_device.DataList[1]  =info.DataList[1]
		_device.HeartCount += 1
		_device.PowerEnenge = info.PowerEnenge
		_device.ShortAddr = info.ShortAddr
		return 200
	}else{
		//beego.Info("heartbeat deivce not exit,")
		return 100;
	}

}

//查询设备是否在连接池中
//@param mac  string   设备的mac地址
func isDeviceExist(device DeviceScript) bool {

	data, ok := devices[device.GateMac].DeviceInfoMap[device.Device_Info.DeviceID]
	if ok {
		fmt.Println("Found device", data, "with DeviceID:",device.Device_Info.DeviceID)
		return true
	} else {
		fmt.Println("Did not find device with DeviceID",device.Device_Info.DeviceID)
		return false
	}
}


func isDevicesExist(DeviceID string)  (DeviceInfo ,bool) {
	for k, v := range (devices) {
		data, ok := v.DeviceInfoMap[DeviceID]
		if ok {
			fmt.Println("Found device in mac ", k, "with DeviceID:", DeviceID,"BindID",data.BindID)
			return data,true
		}
	}
	return DeviceInfo{},false

}
//查询网关是否在连接池中
//@param mac  string   设备的mac地址
func isGatewayExist(mac  string) bool {

	_, ok := devices[mac]
	if ok {
		fmt.Println("Found gateway with mac:",mac)
		return true
	}else {
		fmt.Println("Did not find gateway with mac",mac)
		return false
	}
}

//连接池的事件处理中心
func device_pool() {
	for {
		select {
		case dev := <-subscribe:
			fmt.Printf("chatroom subscribe event\n")
			if !isDeviceExist(dev) {
				//addChannel()
				//subscribers.PushBack(sub) // Add user to the end of list.
				addDevice(dev)
				//isDeviceExist("3c:15:c2:df:92:80")
			} else {
				beego.Info("Old device:", dev.Device_Info.Mac, ";WebSocket:", dev.Conn != nil)
				replaceGateway(dev)
			}

		case dev := <-unsubscribe:
			fmt.Printf("device unsubscribe event:%s\n",dev.DeviceID)
			removeDevice(dev.Mac,dev.DeviceID)
		case dev := <-subscribe_gateway:
			fmt.Printf("gateway subscribe event\n")
			if !isGatewayExist(dev.GateMac) {
				//addChannel()
				//subscribers.PushBack(sub) // Add user to the end of list.
				addGateway(dev)
				//isDeviceExist("3c:15:c2:df:92:80")
			} else {
				beego.Info("Old device:", dev.GateMac, ";WebSocket:", dev.Conn != nil)
				replaceGateway(dev)
			}

		case gateway_mac := <-unsubscribe_gateway:
			fmt.Printf(" unsubscribe_gateway event:%s\n",gateway_mac)
			removeGateway(gateway_mac)

		case msg := <-msgscribe:
//			if !isDeviceExist(msg) {
//				sendJson(msg.Msg,devices[msg.Mac]);
//			} else {
//				beego.Info("msg event ",msg)
//				//replaceDevice(dev)
//			}
			fmt.Printf("msg scribe event:%s\n",msg)
		case msg := <-heart_msg:
		fmt.Println("heart_msg",msg)
			HeartBeat(msg)
		}
	}
}

func CompareHeartBeat()  {
	for gate_mac, gate := range devices{

		for device_mac, _device := range gate.DeviceInfoMap{
			if _device.LastCollection == -1{
				_device.LastCollection = 0
///				continue
			}else if( _device.LastCollection == 10) {
				map_info := make(map[string] DeviceInfo)
				map_info[device_mac] = _device
				err_devices[device_mac] = DevicePoll{GateMac:gate_mac,DeviceInfoMap:map_info};

			}else{
				if(_device.HeartCount == _device.LastHeartCount){
					_device.LastCollection++
				}else{
					_device.LastHeartCount = _device.HeartCount
				}
			}

		}
	}
}

func CollectErrorDevices() {
	timer1 := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-timer1.C:
			CompareHeartBeat()
		}
	}
}

func init() {
	beego.Debug("start channel")
	go device_pool()
}
